home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 4 / ETO Development Tools 4.iso / Tools - Objects / Macintosh Programmer’s Workshop / MPW QR4 / SADE 1.3b1 / SadeStartup < prev    next >
Text File  |  1991-04-25  |  27KB  |  833 lines

  1. ##########################################################################################
  2. #    Symbolic Application Debugging Environment    1.3
  3. #
  4. #    Copyright Apple Computer, Inc. 1987-1991
  5. #    All rights reserved.
  6. #
  7. ##########################################################################################
  8. #
  9. # SADEStartup -- default OnEntry mechanism and support for source level debugging.
  10. #
  11.  
  12. #
  13. # The following variables are used by the OnEntry and source & variable display mechanism.
  14. #
  15. define __SourceDbg__     := 1             # controls source vs. low-level debugging
  16. define __MaxWatchVars__  := 10           # maximum number of watched variables
  17. define __NumWatchVars__  := 0            # current number of watch variables
  18. define __WatchVar__[__MaxWatchVars__]   # names of variables to watch
  19. define __MaxBreakifs__   := 10           # maximum number of conditional breaks
  20. define __BreakifAddr__[__MaxBreakifs__] # conditional break addresses
  21. define __BreakifCond__[__MaxBreakifs__] # conditional break conditions
  22. define __i__
  23. for __i__ := 1 to __MaxBreakifs__ do
  24.     __BreakifAddr__[__i__] := 0
  25. end
  26. define SADEDir := WorksheetWindow
  27. for __i__ := length(SADEDir) downto 1 do
  28.     if copy(SADEDir, __i__, 1) = ':' then
  29.         SADEDir := copy(SADEDir, 1, __i__)
  30.         leave
  31.     end
  32. end
  33. undefine __i__
  34.  
  35. # This sets the size of new windows [top, left, bottom, right]
  36. WindowSize New 0, 0, 200, 200
  37.  
  38. #
  39. # You may change the default values below to change how source level displays work.
  40. #
  41. define __SourceInFront__ := 1    # controls whether source will be brought up as frontmost window
  42.  
  43. # Set this if you want an alert on hitting a breakpoint.
  44. define Breakalert := 0    # controls breakpoint alert
  45.  
  46. # Set __WantStackWindow__ to 1 if you want a live Stack window which updates every
  47. # time you step.  Since this slows things down, you may prefer to leave it 0 and just
  48. # ask for a snapshot of the stack when you need to.
  49. define __WantStackWindow__ := 0         # controls stack display
  50.  
  51. proc ToggleWantStackWindow
  52.     if __WantStackWindow__ = 0 then
  53.         __WantStackWindow__ := 1
  54.         open concat(SADEDir, "Stack")
  55.         addmenu 'Variables' '!Live Stack Window' 'ToggleWantStackWindow'     # '' is control-r (a checkmark)
  56.     else
  57.         __WantStackWindow__ := 0
  58.         save concat(SADEDir, "Stack")
  59.         close concat(SADEDir, "Stack")
  60.         addmenu 'Variables' 'Live Stack Window' 'ToggleWantStackWindow'
  61.     end
  62. end
  63.  
  64. proc __Fail__(__ErrorString__)
  65.     Alert __ErrorString__
  66.     redirect pop
  67.     Abort
  68. end
  69.  
  70. # Set __WantRegisterWindow__ to 1 if you want a live Registers window which updates every
  71. # time you step.  Since this slows things down, you may prefer to leave it 0 and just
  72. # ask for a snapshot of the registers when you need to.
  73. define __WantRegisterWindow__ := 0         # controls register display
  74.  
  75. proc ToggleWantRegisterWindow
  76.     if __WantRegisterWindow__ = 0 then
  77.         __WantRegisterWindow__ := 1
  78.         open concat(SADEDir, "Registers")
  79.         addmenu 'Variables' '!Live Register Window' 'ToggleWantRegisterWindow'     # '' is control-r (a checkmark)
  80.     else
  81.         __WantRegisterWindow__ := 0
  82.         close concat(SADEDir, "Registers")
  83.         addmenu 'Variables' 'Live Register Window' 'ToggleWantRegisterWindow'
  84.     end
  85. end
  86.  
  87. #
  88. # You can set the Safety variable to 1 if you want SADE to be more careful
  89. # when stepping and breaking.  The default setting slightly increases the
  90. # possibility of SADE crashing because of a memory stomper in user code,
  91. # but makes stepping and breaking ten times faster.
  92. #
  93. Safety := 0
  94.  
  95. #
  96. # By default, BreakifNoSource is false.  This allows SADE to step
  97. # through routines like LMODT and UDIVT.  It also lets SADE step
  98. # through Object Pascal and MacApp method dispatch code.  However, 
  99. # if you have enabled symbolics for only a small portion of your
  100. # code and do a step into, it will appear that SADE has hung when
  101. # it is really single stepping through zillions of instructions.
  102. # The default setting of 0 supports MacApp and avoids mystery
  103. # breaks in LMODT.  See the "SADE New User WorkSheet" for details.
  104. BreakifNoSource := 0
  105.  
  106. proc ToggleBreakifNoSource
  107.     if BreakifNoSource = 0 then
  108.         BreakifNoSource := 1
  109.         addmenu 'SourceCmds' '!Break if No Source' 'ToggleBreakifNoSource'     # '' is control-r (a checkmark)
  110.     else
  111.         BreakifNoSource := 0
  112.         addmenu 'SourceCmds' 'Break if No Source' 'ToggleBreakifNoSource'
  113.     end
  114. end
  115.  
  116. #
  117. # By default, __StopBeforeStatic__ is 0.  This makes SADE step to
  118. # main.(0) when an application is launched.  If you set it to 1, SADE
  119. # will give you control before any code in the app is run.  You can then
  120. # place breakpoints at your static constructors before you proceed.
  121. #
  122. define __StopBeforeStatic__ := 0
  123.  
  124. proc ToggleStopBeforeStatic
  125.     if __StopBeforeStatic__ = 0 then
  126.         __StopBeforeStatic__ := 1
  127.         addmenu 'File' '!Stop Before Constructor' 'ToggleStopBeforeStatic'
  128.     else
  129.         __StopBeforeStatic__ := 0
  130.         addmenu 'File' 'Stop Before Constructor' 'ToggleStopBeforeStatic'     # '' is control-r (a checkmark)
  131.     end
  132. end
  133.  
  134. # This macro is used by scripts below to check if there is a valid target.
  135. macro CheckNullTarget        'if processId = 0 then;alert "No process targeted.";abort;end'
  136.  
  137. # This macro is used to check if the target is running.
  138. macro CheckRunningTarget    'if TargetRunning then;alert "Target is running.";abort;end'
  139. macro CheckNullOrRunningTarget    'CheckNullTarget;CheckRunningTarget'
  140.  
  141. # This macro is used to see if we are at a "LINK A6, $xxxx" instruction
  142. # (local variables are not valid until after the instruction has executed).
  143. macro PCIsAtLinkA6    '^ΔWord(ΔPC)^ = $4E56'    # LINK opword = $4E56
  144.  
  145. # If we haven't executed the LINK instruction, print a warning.
  146. proc CheckValidLocalVars
  147.     if PCIsAtLinkA6 then
  148.         printf "Note: Parameters and local variables\naren't valid yet at this statement.\n"
  149.     end
  150. end
  151.  
  152. # Return true if the 1st character of __theStr__ is in [A-Z,a-z,_]
  153. func IsAlpha(__theStr__)
  154.     define __theChar__ := copy(__theStr__, 1, 1)
  155.     if (__theChar__ >= 'a') and (__theChar__ <= 'z') then
  156.         return 1
  157.     end
  158.     if (__theChar__ >= 'A') and (__theChar__ <= 'Z') then
  159.         return 1
  160.     end
  161.     if (__theChar__ = '_') then
  162.         return 1
  163.     end
  164.     return 0
  165. end
  166.  
  167. # Add a backquote to the selected name to evaluate it as a program variable.
  168. func BackquotedSelection(__theSelection__)
  169.     if copy(__theSelection__, 1, 1) = '`' then
  170.         return __theSelection__
  171.     end
  172.     if IsAlpha(__theSelection__)
  173.         return concat('`', __theSelection__)
  174.     end
  175.     return __theSelection__
  176. end
  177.  
  178. # Print a variable's name and value, with linebreaks as necessary.
  179. proc PrettyPrintValue(__theSelection__)
  180.     if Length(__theSelection__) = 0 then
  181.         Alert "Selection is zero-length."
  182.         return
  183.     end
  184.     __theSelection__ := BackquotedSelection(__theSelection__)
  185.     define EvaledVar := Eval(__theSelection__, '???')
  186.     if TypeOf(EvaledVar) = 'PString' then
  187.         if EvaledVar = '???' then
  188.             printf "%s = Undefined/Out of scope\n", __theSelection__
  189.             return
  190.         elseif copy(EvaledVar, 1, 21) = '### Eval syntax error' then
  191.             printf "%s = Expression syntax error", __theSelection__
  192.             return
  193.         end
  194.     end
  195.     if Length(__theSelection__) > 20 then
  196.         printf "%s =\n%t\n", __theSelection__, EvaledVar
  197.     else
  198.         printf "%s = %t\n", __theSelection__, EvaledVar
  199.     end
  200. end
  201.  
  202. # Print a variable's name and its value in hex, with linebreaks as necessary.
  203. proc PrettyPrintValueInHex(__theSelection__)
  204.     if Length(__theSelection__) = 0 then
  205.         Alert "Selection is zero-length."
  206.         return
  207.     end
  208.     __theSelection__ := BackquotedSelection(__theSelection__)
  209.     define EvaledVar := Eval(__theSelection__, '???')
  210.     if TypeOf(EvaledVar) = 'PString' then
  211.         if EvaledVar = '???' then
  212.             printf "%s = Undefined/Out of scope\n", __theSelection__
  213.             return
  214.         elseif copy(EvaledVar, 1, 21) = '### Eval syntax error' then
  215.             printf "%s = Expression syntax error", __theSelection__
  216.             return
  217.         else
  218.             printf "Printing strings as hex values does not work well.\n"
  219.         end
  220.     end
  221.     if SizeOf(EvaledVar) > 4 then
  222.         printf "Printing of non-integral objects as hex values does not work well.\n"
  223.         printf "%s =\n$%X\n", __theSelection__, EvaledVar
  224.     else
  225.         printf "%s = $%X\n", __theSelection__, EvaledVar
  226.     end
  227. end
  228.  
  229. # Display the watch variables.
  230. proc DisplayWatchVars
  231.     define __i__
  232.     open behind concat(SADEDir, "Variable Watch")
  233.     redirect concat(SADEDir, "Variable Watch")
  234.     CheckValidLocalVars
  235.     for __i__ := 1 to __NumWatchVars__ do
  236.         PrettyPrintValue(__WatchVar__[__i__])
  237.     end
  238.     redirect pop
  239. end
  240.  
  241. #
  242. # Register display -- the Registers and DisplayRegs procs
  243. #
  244. proc Registers
  245.     printf "D0: $%.8X\nD1: $%.8X\nD2: $%.8X\nD3: $%.8X\nD4: $%.8X\nD5: $%.8X\nD6: $%.8X\nD7: $%.8X\n\n", ΔD0, ΔD1, ΔD2, ΔD3, ΔD4, ΔD5, ΔD6, ΔD7
  246.     printf "A0: $%.8X\nA1: $%.8X\nA2: $%.8X\nA3: $%.8X\nA4: $%.8X\nA5: $%.8X\nA6: $%.8X\nA7: $%.8X\n\n", ΔA0, ΔA1, ΔA2, ΔA3, ΔA4, ΔA5, ΔA6, ΔA7
  247.     printf "PC: $%.8X\n\n", ΔPC
  248.     printf "\tXNZVC\n"
  249.     printf "CCR\t%.5b\n", ΔCCR & $1F
  250. end
  251.  
  252. proc DisplayRegs
  253.     CheckNullTarget
  254.     if TargetRunning then
  255.         alert "The target is running.  You must halt it to see its registers."
  256.         abort
  257.     end
  258.     open concat(SADEDir, "Registers")
  259.     SizeWindow To 160, 295 concat(SADEDir, "Registers")
  260.     redirect concat(SADEDir, "Registers")
  261.     Registers
  262.     redirect pop
  263. end
  264.  
  265. #
  266. # Stack display -- the DoStack and DisplayStack procs
  267. #
  268. proc DoStack
  269.     if PCIsAtLinkA6 then
  270.         printf "Stack isn't valid yet at this statement.\n"
  271.     else
  272.         stack
  273.     end
  274. end
  275.  
  276. proc DisplayStack
  277.     CheckNullTarget
  278.     if TargetRunning then
  279.         alert "The target is running.  You must halt it to see its stack."
  280.         abort
  281.     end
  282.     open concat(SADEDir, "Stack")
  283.     redirect concat(SADEDir, "Stack")
  284.     DoStack
  285.     redirect pop
  286. end
  287.  
  288.  
  289. #••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••
  290. #
  291. # Entry handling -- the StandardEntry proc
  292. #
  293. macro kSEprocessLoaded        '65'
  294. macro kSETrace                '51'
  295. macro kSEAddressBreak        '58'
  296. macro kSESADEKeyInterrupt    '55'
  297. macro kSEprocessHalted        '8194'
  298.  
  299. func GetErrorString()
  300.     define __errCause__ := ''
  301.     if Exception = kSETrace then
  302.         __errCause__ := "Instruction trace"
  303.     elseif Exception = kSEAddressBreak then
  304.         __errCause__ := "Address Break encountered"
  305.     elseif Exception = 50 then
  306.         __errCause__ := "Trap Break encountered"
  307.     elseif (Exception = kSESADEKeyInterrupt) | (Exception = 13) then 
  308.         __errCause__ := "Program interrupted"
  309.     elseif (Exception = kSEprocessHalted) then 
  310.         __errCause__ := "process Halted"
  311.     elseif Exception = 1 then
  312.         __errCause__ := "Bus Error"
  313.     elseif Exception = 2 then
  314.         __errCause__ := "Address Error"
  315.     elseif Exception = 3 then
  316.         __errCause__ := "Illegal instruction encountered"
  317.     elseif Exception = 4 then
  318.         __errCause__ := "Divide by zero encountered"
  319.     elseif Exception = 5 then
  320.         __errCause__ := "CHK exception (array index out of range) encountered"
  321.     elseif Exception = 6 then
  322.         __errCause__ := "TRAPV or TRAPcc instruction encountered"
  323.     elseif Exception = 7 then
  324.         __errCause__ := "Privilege Violation"
  325.     elseif Exception = 63 then
  326.         __errCause__ := "Internal non-fatal error!  You may be able to proceed..."
  327.     elseif Exception = 64 then
  328.         __errCause__ := "Internal fatal error!  Please kill the target process!"
  329.     elseif Exception = kSEprocessLoaded then
  330.         __errCause__ := "Initial program break encountered"
  331.     elseif Exception = -490 then
  332.         __errCause__ := "User Break encountered"
  333.     elseif Exception = -491 then
  334.         __errCause__ := concat ("∂"", ^PString(ΔSP^)^, "∂"")
  335.         ΔSP := ΔSP+4;
  336.     elseif Exception = -492 then
  337.         __errCause__ := concat ("Execute message not implemented ∂"", ^PString(ΔSP^)^, "∂"")    # currently no way to execute this from SADE!
  338.         ΔSP := ΔSP+4;
  339.     elseif Exception = -490 then
  340.         __errCause__ := "User Break encountered"
  341.     else
  342.         __errCause__ := concat('Error number ', Exception)
  343.     end
  344.     return __errCause__
  345. end
  346.  
  347. proc StandardEntry
  348.     define __errCause__ := GetErrorString();
  349.     
  350.     if __SourceDbg__ then
  351.         if addrToSource(ΔPC, __SourceInFront__) and (Exception > 0) then
  352.             if Exception <> kSETrace then
  353.                 if Breakalert then 
  354.                     alert concat(__errCause__, ' at ', where(ΔPC))
  355.                 elseif (Exception <> kSEprocessLoaded) and (Exception <> kSEAddressBreak) and (Exception <> kSESADEKeyInterrupt) then
  356.                     alert concat(__errCause__, ' at ', where(ΔPC))
  357.                 end
  358.             end
  359.         else
  360.             # if we are at the startup code for a C program, move ahead to main.(0)
  361.             if (Exception = kSEprocessLoaded) and (eval('main.(0)', '????') <> '????') then
  362.                 if (__StopBeforeStatic__ = 0) then
  363.                     go til main.(0)
  364.                     stop
  365.                 else
  366.                     printf "\n%s at %t\n", __errCause__, where(ΔPC)
  367.                     stop
  368.                 end
  369.             else
  370.                 open WorksheetWindow
  371.                 redirect append concat(WorksheetWindow, '.§')
  372.                 printf "\n%t in ""%t""\n", __errCause__, ^Δpstring(@ΔCurApName)^
  373.                 disasm ΔPC 1
  374.                 redirect pop
  375.             end
  376.         end
  377.     else        # Assembly mode
  378.         if Exception <> kSETrace then
  379.             printf "\n%t in ""%t""\n", __errCause__, ^Δpstring(@ΔCurApName)^
  380.         end
  381.         disasm ΔPC 1
  382.     end
  383.     
  384.     if __NumWatchVars__ > 0 then
  385.         DisplayWatchVars
  386.     end
  387.  
  388.     if __WantStackWindow__ > 0 then
  389.         redirect concat(SADEDir, "Stack")
  390.         DoStack
  391.         redirect pop
  392.     end
  393.  
  394.     if __WantRegisterWindow__ > 0 then
  395.         redirect concat(SADEDir, "Registers")
  396.         Registers
  397.         redirect pop
  398.     end
  399. end
  400.  
  401. OnEntry StandardEntry
  402.  
  403.  
  404. #
  405. #
  406. # Killing or untargeting the target
  407. # Killing a target means to terminate it.  Untargeting it, however, simply means for
  408. # SADE to stop treating it as a target.  The semantics of untargeting are as follows:
  409. # if the target is running, it is left running.  If it is suspended at a breakpoint, 
  410. # it is restarted.  If it is suspended due to a "hard" exception (e.g. a bus error), 
  411. # it is killed.
  412. # Care is required in killing MPW tools.  Since in debugging a tool SADE's target is
  413. # actually the MPW shell, the kill command will kill the shell as well as the tool.
  414. # To avoid this, the KillTool proc below will kill a suspended tool without killing
  415. # the shell.  (KillTool won't kill a running tool.)  The KillTarget proc checks the
  416. # type of the target and executes either Kill or KillTool as appropriate.
  417. #
  418.  
  419. proc UnTarget
  420.     Target ''
  421. end
  422.  
  423. proc KillTool
  424.     ΔPC := @µSYSRECOVER                # set the pc to the shell's error recovery routine
  425.     go
  426. end
  427.  
  428. proc KillTarget
  429.     if TargetIsMPWTool then
  430.         KillTool
  431.     else
  432.         kill
  433.     end
  434. end
  435.  
  436.  
  437. #
  438. # Macsbug equivalent command names for SADE
  439. # if you want these, remove the leading comments.
  440. # NOTE that these macros will be found before any program variables
  441. # of the same name!
  442. #
  443. # macro    g         "go"
  444. # macro    il        "disasm"
  445. # macro    ip        "disasm ΔPC-20 40"
  446. # macro    br        "break"
  447. # macro    ht        "heap totals"
  448. # macro    hd        "heap display"
  449. # macro    atba    "break all traps from applzone..applzone^"
  450. # macro    mc        "macro"
  451. # macro    id        "disasm"
  452. # macro    sc        "stack"
  453. # macro td        "registers"
  454.  
  455. #
  456. # Source Breakpoints
  457. #
  458. proc SetSourceBreak
  459.     CheckNullTarget
  460.     define __sourceBreak__ := sourceToAddr(activeWindow, 1)
  461.     if typeof(__sourceBreak__) = 'PString' then
  462.         alert concat('Cannot determine break address: ', __sourceBreak__)
  463.     else
  464.         break __sourceBreak__
  465.         if not addrToSource(__sourceBreak__, 1) then    # verify statement selection
  466.             alert 'Able to set but not display breakpoint; SourcePath may not be set'
  467.         end
  468.     end
  469. end
  470.  
  471. proc ProcessBreakIf        # used by SetSourceBreakIf below
  472.     define __i__, __addr__
  473.     for __i__ := 1 to __MaxBreakifs__ do
  474.         if (__addr__ := __BreakifAddr__[__i__]) <> 0 then
  475.             if __addr__ = ΔPC then
  476.                 if eval(__BreakifCond__[__i__]) then
  477.                     stop
  478.                 end
  479.             end
  480.         end
  481.     end
  482. end
  483.  
  484. proc SetSourceBreakIf
  485.     CheckNullTarget
  486.     define __i__, __j__, __condition__, __EvaledCondition__
  487.     define __sourceBreak__ := sourceToAddr(activeWindow, 1)
  488.     if typeof(__sourceBreak__) = 'PString' then
  489.         alert concat('Cannot determine break address: ', __sourceBreak__)
  490.     else
  491.         if (__condition__ := request('Condition to break on?')) = '_CANCEL_' then
  492.             return
  493.         elseif __condition__ = '' then
  494.             alert 'No condition was specified; break not set'
  495.         else
  496.             # check for valid condition
  497.             __EvaledCondition__ := eval(__condition__, '???')
  498.             if typeof(__EvaledCondition__) = 'PString' then
  499.                 if __EvaledCondition__ = '???' then
  500.                     if not confirm('Variable not defined in current scope.  Still set conditional break?') then
  501.                         return
  502.                     end
  503.                 elseif copy(__EvaledCondition__, 1, 21) = '### Eval syntax error' then
  504.                     alert concat('Cannot set conditional break.  Expression syntax error: ', __condition__)
  505.                     return
  506.                 end
  507.             end
  508.             for __i__ := 1 to __MaxBreakifs__ + 1 do        # try to add to conditional break table
  509.                 if __i__ = (__MaxBreakifs__ + 1) then
  510.                     if confirm('Conditional break table full; remove previous breaks?') then
  511.                         for __j__ := 1 to __MaxBreakifs__ do
  512.                             unbreak __BreakifAddr__[__j__]
  513.                             __BreakifAddr__[__j__] := 0
  514.                         end
  515.                         __BreakifAddr__[1] := __sourceBreak__
  516.                         __BreakifCond__[1] := __condition__
  517.                         leave
  518.                     end
  519.                     return
  520.                 elseif (__BreakifAddr__[__i__] = 0) | (__sourceBreak__ = __BreakifAddr__[__i__]) then
  521.                     __BreakifAddr__[__i__] := __sourceBreak__
  522.                     __BreakifCond__[__i__] := __condition__
  523.                     leave
  524.                 end
  525.             end
  526.         end
  527.         break __sourceBreak__ processBreakIf
  528.         if not addrToSource(__sourceBreak__, 1) then    # verify statement selection
  529.             alert 'Able to set but not display breakpoint; SourcePath may not be set'
  530.         end
  531.     end
  532. end
  533.  
  534. proc UnSetSourceBreak
  535.     CheckNullTarget
  536.     define __i__
  537.     define __sourceBreak__ := sourceToAddr(activeWindow, 1)
  538.     if typeof(__sourceBreak__) = 'PString' then
  539.         alert concat('Cannot determine break address: ', __sourceBreak__)
  540.     else
  541.         unbreak __sourceBreak__
  542.         for __i__ := 1 to __MaxBreakifs__ do                # remove from Breakif table if present
  543.             if __sourceBreak__ = __BreakifAddr__[__i__] then
  544.                 __BreakifAddr__[__i__] := 0
  545.                 leave
  546.             end
  547.         end
  548.         if addrToSource(__sourceBreak__, 1) then; end    # verify statement selection
  549.     end
  550. end
  551.  
  552. proc StepMenu
  553.     CheckNullOrRunningTarget
  554.     if __SourceDbg__ = 0 then
  555.         step asm
  556.     else
  557.         step
  558.     end
  559. end
  560.  
  561. proc StepIntoMenu
  562.     CheckNullOrRunningTarget
  563.     if __SourceDbg__ = 0 then
  564.         step asm into
  565.     else
  566.         step into
  567.     end
  568. end
  569.  
  570. proc StepOut
  571.     CheckNullOrRunningTarget
  572.     if PCIsAtLinkA6    then    # we are looking at a LINK instruction- A6 has not been set up
  573.         go til (ΔA7)^        # but ΔA7 probably contains the right value
  574.     else                    # a LINK has already taken place
  575.         go til (ΔA6+4)^
  576.     end
  577. end
  578.  
  579. proc GoTil
  580.     CheckNullOrRunningTarget
  581.     define __sourceBreak__ := sourceToAddr(activeWindow, 1)
  582.     if typeof(__sourceBreak__) = 'PString' then
  583.         alert concat('Cannot determine break address: ', __sourceBreak__)
  584.     else
  585.         go til __sourceBreak__
  586.     end
  587. end
  588.  
  589. proc InWhatStatement
  590.     CheckNullOrRunningTarget
  591.     if NOT addrToSource(ΔPC, __SourceInFront__) then
  592.         alert "Cannot find source for PC."
  593.     end
  594. end
  595.  
  596. proc ShowWhere
  597.     define __loc__
  598.     CheckNullTarget
  599.     __loc__ := sourceToAddr(ActiveWindow, 1)
  600.     if typeof(__loc__) = 'PString' then
  601.         alert concat('Cannot determine address from source: ', __loc__)
  602.     else
  603.         alert concat('At ', where(__loc__))
  604.     end
  605. end
  606.  
  607. proc ShowSource(__theSelection__)
  608.     CheckNullTarget
  609.     define __theFunc__ := eval(__theSelection__, '???')
  610.     if typeof(__theFunc__) = 'PString' then
  611.         if __theFunc__ = '???' then
  612.             alert concat('"', __theSelection__, '" is not a function or procedure name which is known at this point.')
  613.         else
  614.             alert concat('"', __theSelection__, '" is not a function or procedure name.')
  615.         end
  616.         abort
  617.     end
  618.     if typeof(__theFunc__) <> 'CodeModule' then
  619.         alert concat('"', __theSelection__, '" is not a function or procedure.')
  620.     elseif not addrToSource(__theFunc__, 1) then
  621.         alert concat('The source for "', __theSelection__, '" could not be found.')
  622.     end
  623. end
  624.  
  625. proc ToggleSourceDbg
  626.     if __SourceDbg__ = 0 then
  627.         __SourceDbg__ := 1
  628.         deletemenu 'SourceCmds' '!Asm [vs. Source] Debugging'     # '' is control-r (a checkmark)
  629.         addmenu 'SourceCmds' '!Source [vs. Asm] Debugging' 'ToggleSourceDbg'     # '' is control-r (a checkmark)
  630.     else
  631.         __SourceDbg__ := 0
  632.         deletemenu 'SourceCmds' '!Source [vs. Asm] Debugging'     # '' is control-r (a checkmark)
  633.         addmenu 'SourceCmds' '!Asm [vs. Source] Debugging' 'ToggleSourceDbg'     # '' is control-r (a checkmark)
  634.     end
  635. end
  636.  
  637. proc ShowValue(__theSelection__)
  638.     CheckNullTarget
  639.     open concat(SADEDir, "Values")
  640.     redirect append concat(SADEDir, "Values")
  641.     CheckValidLocalVars
  642.     PrettyPrintValue(__theSelection__)
  643.     redirect pop
  644. end
  645.  
  646. proc ShowValueInHex(__theSelection__)
  647.     CheckNullTarget
  648.     open concat(SADEDir, "Values")
  649.     redirect append concat(SADEDir, "Values")
  650.     CheckValidLocalVars
  651.     PrettyPrintValueInHex(__theSelection__)
  652.     redirect pop
  653. end
  654.  
  655. proc __CheckPointer__(__theSelection__)
  656.     define __ErrorMessage__
  657.     define __EvaledPointer__ := eval(__theSelection__, '????')
  658.     if typeof(__EvaledPointer__) = 'PString' then
  659.         if __EvaledPointer__ = '????' then
  660.             __ErrorMessage__ := ": Undefined"
  661.         elseif copy(__EvaledPointer__, 1, 21) = '### Eval syntax error' then
  662.             __ErrorMessage__ := ": Syntax Error"
  663.         end
  664.         __ErrorMessage__ := concat(__theSelection__, __ErrorMessage__)
  665.         __Fail__(__ErrorMessage__)
  666.     end
  667.     if sizeof(__EvaledPointer__) <> 4 then
  668.         __Fail__(concat(__theSelection__, " is not a pointer."))
  669.     end
  670.     if eval(__theSelection__) = 0 then
  671.         __ErrorMessage__ := concat(concat("Cannot dereference ", __theSelection__), ' = 0')
  672.         __Fail__(__ErrorMessage__)
  673.     end    
  674. end
  675.  
  676. proc ShowDereferencedValue(__theSelection__)
  677.     CheckNullTarget
  678.     __theSelection__ := BackquotedSelection(__theSelection__)
  679.     __CheckPointer__(__theSelection__)
  680.     ShowValue(concat(__theSelection__, '^'))
  681. end
  682.  
  683. proc ShowDereferencedValueInHex(__theSelection__)
  684.     CheckNullTarget
  685.     __theSelection__ := BackquotedSelection(__theSelection__)
  686.     __CheckPointer__(__theSelection__)
  687.     ShowValueInHex(concat(__theSelection__, '^'))
  688. end
  689.  
  690. proc AddWatchVar(__theSelection__)
  691.     CheckNullTarget
  692.     define __EvaluedExpr__
  693.     if __NumWatchVars__ >= __MaxWatchVars__ then
  694.         alert "Cannot add more watch variables"
  695.     else
  696.         __theSelection__ := BackquotedSelection(__theSelection__)
  697.         __EvaluedExpr__ := Eval(__theSelection__, '???')
  698.         if typeof(__EvaluedExpr__) = 'PString' then
  699.             if copy(__EvaluedExpr__, 1, 21) = '### Eval syntax error' then
  700.                 alert concat('Cannot add watch variable.  Expression syntax error: ', __theSelection__)
  701.                 return
  702.             elseif __EvaluedExpr__ = '???' then
  703.                 if not confirm(concat(__theSelection__, ' not defined at this time.  Still add as watch variable?')) then
  704.                     return
  705.                 end
  706.             end
  707.         end
  708.         __NumWatchVars__ := __NumWatchVars__ + 1
  709.         __WatchVar__[__NumWatchVars__] := __theSelection__
  710.         # Now refresh the display window
  711.         DisplayWatchVars
  712.     end
  713. end
  714.  
  715.  
  716. proc DeleteWatchVar(__theSelection__)
  717.     CheckNullTarget
  718.     define __i__, __found__ := 0
  719.     __theSelection__ := BackquotedSelection(__theSelection__)
  720.     for __i__ := 1 to __NumWatchVars__ do
  721.         if __found__ then
  722.             __WatchVar__[__i__-1] := __WatchVar__[__i__]
  723.         elseif __theSelection__ = __WatchVar__[__i__] then
  724.             __found__ := 1
  725.         end
  726.     end
  727.     if __found__ then
  728.         __WatchVar__[__NumWatchVars__] := 0
  729.         __NumWatchVars__ := __NumWatchVars__ - 1
  730.         # Now refresh the display window
  731.         DisplayWatchVars
  732.     else
  733.         alert concat('Cannot find watch variable "', __theSelection__, '" to delete')
  734.     end
  735. end
  736.  
  737. proc DeleteAllWatchVars
  738.     CheckNullTarget
  739.     __NumWatchVars__ := 0
  740.     open behind concat(SADEDir, "Variable Watch")    # These two lines erase window
  741.     redirect concat(SADEDir, "Variable Watch")
  742.     redirect pop
  743. end
  744.  
  745.  
  746. proc SADEHelp(__theSelection__)  # contributed by Bob E., DSG.  Thanks Bob.
  747.     redirect concat(SADEDir, "SADE_Info")
  748.     printf "#   Select a word and then choose the SADE Help menu item.\n"
  749.     printf "#       try:  BuiltIns   Commands   Expressions  Patterns\n"
  750.     printf "#          :  Shortcuts  Variables  Basetypes    <commandName>\n\n"
  751.     #
  752.     if __theSelection__ = '' then
  753.         __theSelection__ := "Commands"
  754.     end
  755.     help expr(__theSelection__)
  756.     redirect pop
  757.     open concat(SADEDir, "SADE_Info")
  758.     define __dummy__
  759.     __dummy__ := selection(concat(SADEDir, "SADE_Info"), 0, 0)
  760. end
  761.  
  762.  
  763.  
  764. #
  765. #
  766. # SADE menu initialization
  767. # Sets up SourceCmds and Variables menus, and adds Kill, Quit, and Help items
  768. # to the File menu.
  769. #
  770. #
  771.  
  772. addmenu 'File' 'Stop Before Constructor'                'ToggleStopBeforeStatic'
  773.  
  774. # You can use the commented-out form if you would like a cmd-K equivalent
  775. # for the Kill menu item.
  776. #addMenu 'File' '(Kill /K'                                'KillTarget'
  777. addMenu 'File' '(Kill'                                    'KillTarget'
  778. addMenu 'File' '(-'                                        ''
  779.  
  780. # The quit command asks you for each dirty file whether to save before quitting.
  781. # SaveAllAndQuit saves all files before quitting.  Use the commented-out form if
  782. # you'd rather be prompted than save automatically.
  783.  
  784. proc SaveAllAndQuit
  785.     save all
  786.     quit
  787. end
  788.  
  789. #addMenu 'File' 'Quit /Q'                                'quit'
  790. addMenu 'File' 'Quit /Q'                                'SaveAllAndQuit'
  791.  
  792. addMenu 'Find' '(-'                                        ''
  793. addMenu 'Find' 'SADE Help/1'                             'SADEHelp(selection(ActiveWindow))'
  794.  
  795. addmenu 'SourceCmds' 'Break /B'                           'SetSourceBreak'
  796. addmenu 'SourceCmds' 'Break if…/∫'                        'SetSourceBreakIf'
  797. addmenu 'SourceCmds' 'Unbreak /U'                         'UnSetSourceBreak'
  798. addmenu 'SourceCmds' 'Unbreak All'                        'unbreak all'
  799. addmenu 'SourceCmds' '(-'                                 ''
  800. addmenu 'SourceCmds' 'Step /L'                            'StepMenu'
  801. addmenu 'SourceCmds' 'Step Into /¬'                       'StepIntoMenu'        # '¬' is Opt-l
  802. addmenu 'SourceCmds' 'Step Out'                           'StepOut'
  803. addmenu 'SourceCmds' '(-'                                 ''
  804. addmenu 'SourceCmds' 'Go /P'                              'go'
  805. addmenu 'SourceCmds' 'Go Til /π'                         'GoTil'
  806. addmenu 'SourceCmds' '(-'                                 ''
  807. addMenu 'SourceCmds' 'In What Statement? /I'            'InWhatStatement'
  808. addMenu 'SourceCmds' 'Statement Selected Is?'            'ShowWhere'
  809. addMenu 'SourceCmds' 'Show Selected Routine'            'ShowSource(selection(ActiveWindow))'
  810. addmenu 'SourceCmds' '(-'                                ''
  811. addmenu 'SourceCmds' 'Break if No Source'                'ToggleBreakifNoSource'
  812. addmenu 'SourceCmds' '!Source [vs. Asm] Debugging'        'ToggleSourceDbg'     # '' is control-r (a checkmark)
  813.  
  814. addmenu 'Variables'  'Show Value /√'                    'ShowValue(selection(ActiveWindow))'    # '√' is Opt-v
  815. addmenu 'Variables'  'Show Dereferenced Value /◊'        'ShowDereferencedValue(selection(ActiveWindow))'    # '◊' is Opt-shift-v
  816. addmenu 'Variables'  'Show Value in Hex'                'ShowValueInHex(selection(ActiveWindow))'
  817. addmenu 'Variables'  'Show Dereferenced Value in Hex'    'ShowDereferencedValueInHex(selection(ActiveWindow))'
  818. addmenu 'Variables'  '(-'                                ''
  819. addmenu 'Variables'  'Add Watch Variable'                'AddWatchVar(selection(ActiveWindow))'
  820. addmenu 'Variables'  'Delete Watch Variable'            'DeleteWatchVar(selection(ActiveWindow))'
  821. addmenu 'Variables'  'Delete All Watch Variables'        'DeleteAllWatchVars'
  822. addmenu 'Variables'  '(-'                                ''
  823. addmenu 'Variables'  'Show Registers'                    'DisplayRegs'
  824. addmenu 'Variables'  'Live Register Window'                'ToggleWantRegisterWindow'
  825. addmenu 'Variables'  '(-'                                ''
  826. addmenu 'Variables'  'Show Stack'                        'DisplayStack'
  827. addmenu 'Variables'  'Live Stack Window'                'ToggleWantStackWindow'
  828.  
  829. #
  830. # Execute SADEUserStartup, where you can add to and modify the stuff supplied here.
  831. #
  832. execute ':SADEUserStartup'
  833.